﻿using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using Maestro_Proveedores.evaluacionDeDesempeno.indicadores;
using System.Data;

namespace Maestro_Proveedores.evaluacionDeDesempeno
{
    /// <remarks>
    /// Esta clase se encarga de realizar la evaluacion de desempeño a los proveedores registrados en el sistema,
    /// Esta clase encapsula todos los conceptos y variables que acarrea esta evaluacion, por ende, sirve como fachada entre todo el 
    /// proceso de evaluacion de desempeño y los demas componentes. Dispone de multiples metodos que retornan objetos DataTable con los resultados dela evalucion.
    /// </remarks>
    public class EvaluacionDeDesempeno
    {
        //private MAPICS.MAPICSDataSetTableAdapters.INF_OCTableAdapter inf_OCTableAdapter = new MAPICS.MAPICSDataSetTableAdapters.INF_OCTableAdapter();
        /// <summary>
        /// Este table adapter se utiliza para filtrar los registros de los proveedores, para mayor informacion puede revisar la definion de CONSULTA_proveedoresTableAdapter.
        /// </summary>
        private _Maestro_Proveedores_CORPORATIVADataSetTableAdapters.CONSULTA_proveedoresTableAdapter cONSULTA_proveedoresTableAdapter = null;
        /// <summary>
        /// Este DataTable se utiliza para almacenar los registros de los proveedores (previamente filtrados) que se le vana a realizar la evaluacion de desempeño.
        /// </summary>
        private _Maestro_Proveedores_CORPORATIVADataSet corPORATIVADataSet = null;
        /// <summary>
        /// Este array tiene almacenados los indicadores que se utilizaran para realizar la evalucion de desempeño a proveedores.
        /// </summary>
        private ArrayList indicadores = null;
        /// <summary>
        /// Este es el DataTable que se retorna con los resultados de la evalucion de desempeño para los proveedores seleccionados
        /// </summary>
        private DataTable datos = null;
        

        public EvaluacionDeDesempeno(){            
            //-- inicializacion de variables.
            this.cONSULTA_proveedoresTableAdapter = new _Maestro_Proveedores_CORPORATIVADataSetTableAdapters.CONSULTA_proveedoresTableAdapter();
            this.corPORATIVADataSet = new  _Maestro_Proveedores_CORPORATIVADataSet();
            this.indicadores = new ArrayList();
            //-- Registro de indicadores.
            this.indicadores.Add(new CumplimientoPlazoEntrega());
            this.indicadores.Add(new CalidadProducto());
            this.indicadores.Add(new CumplimientoUnidadesEntregadas());
            this.indicadores.Add(new CumplimientoServicio());
            this.indicadores.Add(new CalidadServicio());
            this.indicadores.Add(new SeguridadYMedioAmbiente());
            this.indicadores.Add(new Accidentalidad());
            this.indicadores.Add(new ReclamosAtendidos());
            this.indicadores.Add(new NumeroLLamadosAtencion());
        }
        /// <summary>
        /// Evaluar todos los proveedores
        /// </summary>
        /// <param name="fechaInferior">Fecha minima que se tendra en cuenta para realizar la evalución</param>
        /// <param name="fechaSuperior">Fecha maxima que se tendra en cuenta para realizar la evalución</param>
        /// <returns>DataDatble con los resultados de la evaluación.</returns>
        public DataTable evaluarTodos(DateTime fechaInferior, DateTime fechaSuperior)
        {
            //--- esta variable bandera sirve para que las columnas del datatable se agregen una unica vez
            bool ok = false;

            Cursor.Current = Cursors.WaitCursor;
            try
            {
                this.cONSULTA_proveedoresTableAdapter.Fill(this.corPORATIVADataSet.CONSULTA_proveedores);
                foreach (_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row in this.corPORATIVADataSet.CONSULTA_proveedores)
                {
                    //--- le agrego las columnas al datatable, esto se realiza solo una vez
                    if (!ok)
                    {
                        this.crearColumnas(row);
                        ok = true;
                    }
                    //--- le agrego una nueva fila al datatable y le registro los datos basicos del proveedor a la nueva fila
                    this.crearFila(row, fechaInferior, fechaSuperior);
                    //--- realizo la evaluacion
                    this.realizarEvaluacion(row, fechaInferior, fechaSuperior);
                }
            }
            catch (Exception ex)
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
            }
            Cursor.Current = Cursors.Default;
            return this.datos;
        }
        /// <summary>
        /// Evaluar los proveedores filtrados ID del proveedor
        /// </summary>
        /// <param name="idProveedor">ID del proveedor en INFOR XA</param>
        /// <param name="fechaInferior">Fecha minima que se tendra en cuenta para realizar la evalución</param>
        /// <param name="fechaSuperior">Fecha maxima que se tendra en cuenta para realizar la evalución</param>
        /// <returns>DataDatble con los resultados de la evaluación.</returns>
        public DataTable evaluarByIdProveedor(string idProveedor, DateTime fechaInferior, DateTime fechaSuperior)
        {
            //--- esta variable bandera sirve para que las columnas del datatable se agregen una unica vez
            bool ok = false;
            
            Cursor.Current = Cursors.WaitCursor;
            try
            {
                this.cONSULTA_proveedoresTableAdapter.FillByIdProveedor(this.corPORATIVADataSet.CONSULTA_proveedores, idProveedor);
                foreach (_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row in this.corPORATIVADataSet.CONSULTA_proveedores)
                {
                    //MessageBox.Show(row.razon_social);
                    //--- le agrego las columnas al datatable
                    if (!ok)
                    {
                        this.crearColumnas(row);
                        ok = true;
                    }
                    //--- le agrego una nueva fila al datatable y le registro los datos basicos del proveedor a la nueva fila
                    this.crearFila(row, fechaInferior, fechaSuperior);
                    //--- realizo la evaluacion
                    this.realizarEvaluacion(row, fechaInferior, fechaSuperior);

                }
            }
            catch (Exception ex)
            {   
                Maestro_Proveedores.herramientas.MessageException.show(ex);
            }
            Cursor.Current = Cursors.Default;
            return this.datos;
        }
        /// <summary>
        /// Evaluar los proveedores filtrados NIT del proveedor
        /// </summary>
        /// <param name="nitProveedor">NIT del proveedor en INFOR XA</param>
        /// <param name="rangoDeFechas">Rango de fecha en que se realiza la evaluacion, si el rango es "entreFecha", este metodo retornara un DataTable sin registros.</param>
        /// <returns>DataDatble con los resultados de la evaluación.</returns>
        public DataTable evaluarByNitProveedor(string nitProveedor, DateTime fechaInferior, DateTime fechaSuperior)
        {
            //--- esta variable bandera sirve para que las columnas del datatable se agregen una unica vez
            bool ok = false;
            
            Cursor.Current = Cursors.WaitCursor;

            try
            {
                this.cONSULTA_proveedoresTableAdapter.FillByNitProveedor(this.corPORATIVADataSet.CONSULTA_proveedores, nitProveedor);

                foreach (_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row in this.corPORATIVADataSet.CONSULTA_proveedores)
                {
                    //--- le agrego las columnas al datatable
                    if (!ok)
                    {
                        this.crearColumnas(row);
                        ok = true;
                    }
                    //--- le agrego una nueva fila al datatable y le registro los datos basicos del proveedor a dicha fila
                    this.crearFila(row, fechaInferior, fechaSuperior);
                    //--- realizo la evaluacion
                    this.realizarEvaluacion(row, fechaInferior, fechaSuperior);
                }
            }
            catch (Exception ex)
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
            }
            Cursor.Current = Cursors.Default;
            return this.datos;
        }
        /// <summary>
        /// Evaluar los proveedores filtrados por el Tipo y el grupo al que pertenecen
        /// </summary>
        /// <param name="idGrupo">ID del grupo al que pertenecen los proveedores que se desean evaluar</param>
        /// <param name="idTipo">ID del tipo (Bien o Servicio) al que pertenecen los proveedores que se desean evaluar</param>
        /// <param name="rangoDeFechas">Rango de fecha en que se realiza la evaluacion, si el rango es "entreFecha", este metodo retornara un DataTable sin registros.</param>
        /// <returns>DataDatble con los resultados de la evaluación.</returns>
        public DataTable evaluarByIdGrupo(int idGrupo, int idTipo, DateTime fechaInferior, DateTime fechaSuperior)
        {
            //--- esta variable bandera sirve para que las columnas del datatable se agregen una unica vez
            bool ok = false;
            
            Cursor.Current = Cursors.WaitCursor;
            try
            {
                this.cONSULTA_proveedoresTableAdapter.FillByGrupoServicio(this.corPORATIVADataSet.CONSULTA_proveedores, short.Parse(idGrupo.ToString()), short.Parse(idTipo.ToString()));

                foreach (_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row in this.corPORATIVADataSet.CONSULTA_proveedores)
                {
                    //--- le agrego las columnas al datatable
                    if (!ok)
                    {
                        this.crearColumnas(row);
                        ok = true;
                    }
                    //--- le agrego una nueva fila al datatable y le registro los datos basicos del proveedor a dicha fila
                    this.crearFila(row, fechaInferior, fechaSuperior);
                    //--- realizo la evaluacion
                    this.realizarEvaluacion(row, fechaInferior, fechaSuperior);
                }
            }
            catch (Exception ex)
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
            }
            Cursor.Current = Cursors.Default;
            return this.datos;
        }
        /// <summary>
        /// Evaluar los proveedores filtrados por el Tipo al que pertenecen
        /// </summary>
        /// <param name="idTipo">ID del tipo (Bien o Servicio) al que pertenecen los proveedores que se desean evaluar</param>
        /// <param name="fechaInferior">Fecha minima que se tendra en cuenta para realizar la evalución</param>
        /// <param name="fechaSuperior">Fecha maxima que se tendra en cuenta para realizar la evalución</param>
        /// <returns>DataDatble con los resultados de la evaluación.</returns>
        public DataTable evaluarByIdTipo(int idTipo, DateTime fechaInferior, DateTime fechaSuperior)
        {
            //--- esta variable bandera sirve para que las columnas del datatable se agregen una unica vez
            bool ok = false;
            
            Cursor.Current = Cursors.WaitCursor;
            try
            {
                int aux = this.cONSULTA_proveedoresTableAdapter.FillByTipoServicio(this.corPORATIVADataSet.CONSULTA_proveedores, short.Parse(idTipo.ToString()));

                foreach (_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row in this.corPORATIVADataSet.CONSULTA_proveedores)
                {
                    //MessageBox.Show(row.razon_social);

                    //--- le agrego las columnas al datatable
                    if (!ok)
                    {
                        this.crearColumnas(row);
                        ok = true;
                    }
                    //--- le agrego una nueva fila al datatable y le registro los datos basicos del proveedor a dicha fila
                    this.crearFila(row, fechaInferior, fechaSuperior);
                    //--- realizo la evaluacion
                    this.realizarEvaluacion(row, fechaInferior, fechaSuperior);
                }
            }
            catch (Exception ex)
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
            }
            Cursor.Current = Cursors.Default;
            return this.datos;
        }
        /// <summary>
        /// Este metodo es el reponsable de realizar la evalucion de desempeño para cada proveedor.
        /// </summary>
        /// <param name="row">Registro con los datos basicos del proveedor</param>
        /// <param name="rangoDeFechas">Rango de fecha en que se realiza la evaluacion.</param>
        /// <param name="fechaInferior">Fecha minima que se tendra en cuenta para realizar la evalución</param>
        /// <param name="fechaSuperior">Fecha maxima que se tendra en cuenta para realizar la evalución</param>
        /// <returns><para>Retorna True si la evalucion se realiza correctamente.</para><para>Retorna false si se presenta algun error durante la realizacion de la evaluación.</para></returns>
        private bool realizarEvaluacion(_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row, DateTime fechaInferior, DateTime fechaSuperior)
        {
            //-- declaracion e inicializacion de variables
            double totalPonderado = 0;
            double resultTotal = 0;
            double resultTemp = 0;
            double tempResultTemp = 0;
            double tempTotalPonderado = 0;            
            NumeroLLamadosAtencion llamados = new NumeroLLamadosAtencion();
            ReclamosAtendidos reclamos = new ReclamosAtendidos();

            try
            {
                //-- se evalua cada uno de los indicadores
                foreach (Indicador ind in this.indicadores)
                {
                    //-- solo se tendran en cuenta aquellos indicadores que pertenezcan al mismo tipo al que pertenece el proveedor (Bien o Servicio), tambien entran aquellos indicadores que sean del tipo BienServicio.
                    if (ind.TipoIndicador.ToString().ToLower().Contains(row.tipo_servicio.ToLower()) || row.tipo_servicio.ToLower().Contains(ind.TipoIndicador.ToString().ToLower()))
                    {
                        resultTemp = ind.calcularByFechas(row, fechaInferior, fechaSuperior);
                        
                        //--- si el indicador es el de llamados de atencion lo guardo para descontar los puntos porcentuales correspondientes al final
                        if (ind.ToString().Equals(llamados.ToString()))
                        {
                            llamados = (NumeroLLamadosAtencion)ind;
                            //--- registro los resultados en el datatable
                            this.datos.Rows[this.datos.Rows.Count - 1][ind.ToString().ToUpper() + " (Descuento)"] = ind.Resultado;                            
                        }
                        //--- si es el indicador de reclamos atendidos, verifico que se la hayan hecho ordenes de compra al proveedor para aplicarle este indicador.
                        else if (!ind.ToString().Equals(reclamos.ToString())) 
                        {
                            if (!resultTemp.Equals(-1))
                            {
                                //--- registro los resultados en el datatable
                                this.datos.Rows[this.datos.Rows.Count - 1][ind.ToString().ToUpper() + " (Resultado)"] = ind.Resultado;
                                this.datos.Rows[this.datos.Rows.Count - 1][ind.ToString().ToUpper() + " (Calificacion'%')"] = resultTemp / ind.Peso;
                                //---acumulo el total ponderado, y el resultado final ...
                                resultTotal += resultTemp;
                                totalPonderado += ind.Peso;                                
                            }                            
                        }

                        if (ind.ToString().Equals(reclamos.ToString()) && !totalPonderado.Equals(0))
                        {
                            reclamos = (ReclamosAtendidos)ind;
                            //--- registro los resultados en el datatable
                            this.datos.Rows[this.datos.Rows.Count - 1][ind.ToString().ToUpper() + " (Resultado)"] = ind.Resultado;
                            //--- si el indicador no se le definio un peso su resultado sera cero.
                            if (ind.Peso == 0)
                                this.datos.Rows[this.datos.Rows.Count - 1][ind.ToString().ToUpper() + " (Calificacion'%')"] = 0;
                            else
                                this.datos.Rows[this.datos.Rows.Count - 1][ind.ToString().ToUpper() + " (Calificacion'%')"] = resultTemp / ind.Peso;
                            //--- acumulo el total ponderado, y el resultado final ...
                            tempTotalPonderado += ind.Peso;
                            tempResultTemp += resultTemp;
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show("error..");
                Maestro_Proveedores.herramientas.MessageException.show(ex);
                return false;
            }
            //--- si no se le evaluo ningun indicador al proveedor, coloco el resultado de la evaluacion en -1...
            if (totalPonderado.Equals(0))
            {
                this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL(%)"] = "-1";
                this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL"] = "NO HAY REGISTROS";
                return true;
            }
            //--- registro los resultados del indicador de reclamos atendidos
            else if(!tempTotalPonderado.Equals(0))
            {
                this.datos.Rows[this.datos.Rows.Count - 1][reclamos.ToString().ToUpper() + " (Resultado)"] = reclamos.Resultado;
                this.datos.Rows[this.datos.Rows.Count - 1][reclamos.ToString().ToUpper() + " (Calificacion'%')"] = tempResultTemp / reclamos.Peso;
                //---acumulo el total ponderado, y el resultado final ...
                totalPonderado += tempTotalPonderado;
                resultTotal += tempResultTemp;
            }

            //--- registro los resultados finales en el datatable, DESCONTANDOLE lo que le corresponde por el numero de llamados de atencion que tenga
            double rf = (resultTotal / totalPonderado) - (llamados.Resultado);
            this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL(%)"] = rf;
            this.datos.Rows[this.datos.Rows.Count - 1]["TOTAL PONDERADO(%)"] = totalPonderado*100;
            //--- defino el resultado final de la evalucion, deacuerdo a los parametros definidos en el proyecto: DISEÑO E IMPLEMENTACIÓN DEL PROCESO DE CALIFICACIÓN,EVALUACIÓN, DESARROLLO Y CERTIFICACIÓN DE PROVEEDORES DE COTECMAR
            if (rf >= 95) 
                this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL"] = "EXCELENTE";
            else if (rf >= 80)
                this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL"] = "BUENO";
            else if (rf >= 70)
                this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL"] = "REQUIERE MEJORAR";
            else
                this.datos.Rows[this.datos.Rows.Count - 1]["RESULTADO FINAL"] = "NO CUMPLE";
           
            return true;
        }
        /// <summary>
        /// Metodo responsable de crear y definir las columnas del DataTable que se va a retornar con los resultados de la evalucion de desempeño.
        /// </summary>
        /// <param name="row">Registro conlos datos basicos del proveedor a evaluar</param>
        private void crearColumnas(_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row)
        {
            NumeroLLamadosAtencion llamados = new NumeroLLamadosAtencion();
            try
            {
                this.datos = new DataTable();
                datos.Columns.Add("ID", Type.GetType("System.String"));
                datos.Columns.Add("RAZON SOCIAL", Type.GetType("System.String"));
                datos.Columns.Add("NIT", Type.GetType("System.String"));
                datos.Columns.Add("TIPO", Type.GetType("System.String"));
                datos.Columns.Add("GRUPO", Type.GetType("System.String"));
                datos.Columns.Add("SERVICIO_PRINCIPAL", Type.GetType("System.String"));
                datos.Columns.Add("RESULTADO FINAL", Type.GetType("System.String"));
                datos.Columns.Add("RESULTADO FINAL(%)", Type.GetType("System.Double"));
                datos.Columns.Add("VALOR TOTAL($)", Type.GetType("System.Double"));
                datos.Columns.Add("TOTAL PONDERADO(%)", Type.GetType("System.String"));
//MessageBox.Show("ok");
                foreach (Indicador ind in this.indicadores)
                {
                    if (ind.ToString().Equals(llamados.ToString()))
                    {
                        datos.Columns.Add(ind.ToString().ToUpper() + " (Descuento)", Type.GetType("System.Double"));
                    }
                    else if (ind.TipoIndicador.ToString().ToLower().Contains(row.tipo_servicio.ToString().ToLower()) || (row.tipo_servicio.ToString().ToLower()).Contains(ind.TipoIndicador.ToString().ToLower()))
                    {
                        datos.Columns.Add(ind.ToString().ToUpper() + " (Resultado)", Type.GetType("System.Double"));
                        datos.Columns.Add(ind.ToString().ToUpper() + " (Calificacion'%')", Type.GetType("System.Double"));
//MessageBox.Show(ind.ToString().ToUpper());
                    }
                }
            }
            catch(Exception ex)
            {
                herramientas.MessageException.show(ex);
            }
        }
        /// <summary>
        /// Este metodo es el responsable de crear una nueva fila al DataTable que tendra los resultados de la evalucion de desempeño. En este metodo tambien se registran los datos basicos de cada proveedor cada vez que se crea una nueva fila.
        /// </summary>
        /// <param name="row">Registro conlos datos basicos del proveedor a evaluar</param>
        private void crearFila(_Maestro_Proveedores_CORPORATIVADataSet.CONSULTA_proveedoresRow row, DateTime fechaInferior, DateTime fechaSuperior)
        {
            try
            {
                //--- agrego una nuevo fila
                this.datos.Rows.Add(this.datos.NewRow());
                //--- registros los datos basicos del proveedor
                this.datos.Rows[this.datos.Rows.Count - 1]["ID"] = row.id_proveedor.ToString();
                this.datos.Rows[this.datos.Rows.Count - 1]["NIT"] = row.nit_proveedor.ToString();
                this.datos.Rows[this.datos.Rows.Count - 1]["RAZON SOCIAL"] = row.razon_social.ToString();
                this.datos.Rows[this.datos.Rows.Count - 1]["TIPO"] = row.tipo_servicio;
                this.datos.Rows[this.datos.Rows.Count - 1]["GRUPO"] = row.grupo_servicio;
                this.datos.Rows[this.datos.Rows.Count - 1]["SERVICIO_PRINCIPAL"] = row.descripcion_servicio;
                //--- registro el numero total de ordenes de compra en el rango de fechas.
               // this.datos.Rows[this.datos.Rows.Count - 1]["Nº TOTAL DE ORDENES DE COMPRA"] = this.calcularCantidadOC(row.id_proveedor, fechaInferior, fechaSuperior);
                //--- registro el valor total facturado por el proveedor en el rango de fechas.
                this.datos.Rows[this.datos.Rows.Count - 1]["VALOR TOTAL($)"] = this.calcularValorTotal(row.id_proveedor, fechaInferior, fechaSuperior);
            }
            catch (Exception ex)
            {
                herramientas.MessageException.show(ex);
            }
        }
        /// <summary>
        /// Calcular el numero total de ordenes de compra generadas a un proveedor en un rango de fechas
        /// </summary>
        /// <param name="id_proveedor">ID del proveedor</param>
        /// <param name="fechaInferior">Fecha minima</param>
        /// <param name="fechaSuperior">Fecha maxima</param>
        private double calcularCantidadOC(string id_proveedor, DateTime fechaInferior, DateTime fechaSuperior)
        {
            string total = "";
            try
            {
                total = this.corPORATIVADataSet.PRV_EVAL_DESMP.ScalarOT
                                (
                                    id_proveedor,
                                    fechaInferior.Date,
                                    fechaSuperior.Date
                                ).ToString();
                if (total == null && total.Equals(string.Empty))
                    return 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error en la consulta: this.inf_OCTableAdapter.Scalar_totalOC_PRV.\n\n"+ex.Message);
                return -1;
            }
            return double.Parse(total);
        }        
        /// <summary>
        /// Calcular el valor total de todas las ordenes de compra de un proveedor generadas en un rango de fechas
        /// </summary>
        /// <param name="id_proveedor">ID del proveedor</param>
        /// <param name="fechaInferior">Fecha minima</param>
        /// <param name="fechaSuperior">Fecha maxima</param>
        private double calcularValorTotal(string id_proveedor, DateTime fechaInferior, DateTime fechaSuperior) 
        {
            string total = "";
            try
            {
                total = this.corPORATIVADataSet.PRV_EVAL_DESMP.ScalarOT
                                (
                                    id_proveedor,
                                    fechaInferior.Date,
                                    fechaSuperior.Date
                                ).ToString();
                if (total.Equals(string.Empty))
                    return 0;
            }
            catch (Exception) 
            {
                return -1;
            }
            return double.Parse(total);   
        }
    }
}
